spectrum_tf.f90 Source File


Source Code

module spectrum_tf
    use iso_fortran_env
    use spectrum_periodogram
    use spectrum_windows
    implicit none
    private
    public :: siso_transfer_function
    public :: SPCTRM_H1_ESTIMATOR
    public :: SPCTRM_H2_ESTIMATOR

    integer(int32), parameter :: SPCTRM_H1_ESTIMATOR = 50002
        !! A flag for requesting an H1 transfer function estimator.  An H1 
        !! estimator is best used when noise is uncorrelated with the input, 
        !! and results in a transfer function estimate of the form
        !! 
        !! $$ H_{1} = \frac{P_{yx}}{P_{xx}} $$.
    integer(int32), parameter :: SPCTRM_H2_ESTIMATOR = 50003
        !! A flag for requesting an H2 transfer function estimator.  An H2 
        !! estimator is best used when noise is uncorrelated with the output, 
        !! and results in a transfer function estimate of the form
        !! 
        !! $$ H_{2} = \frac{P_{yy}}{P_{xy}} $$.

contains
! ------------------------------------------------------------------------------
! REF: 
! - https://github.com/giuliovv/tfest/blob/main/tfest/tfest.py
! - https://dsp.stackexchange.com/questions/71811/understanding-the-h1-and-h2-estimators
! - https://github.com/epezent/etfe/blob/main/include/ETFE.hpp
function siso_transfer_function(win, x, y, etype, nfft) result(rst)
    !! Estimates the transfer function for a single-input/single-output
    !! (SISO) system.
    class(window), intent(in) :: win
        !! The window object.
    real(real64), intent(in) :: x(:)
        !! An N-element array containing the input signal.
    real(real64), intent(in) :: y(:)
        !! An N-element array containing the output signal.
    integer(int32), intent(in), optional :: etype
        !! An optional input that, if supplied, denotes the
        !! estimator to use.  If no value is specified, an H1 estimator is used.
        !! The following options are supported.
        !!
        !!  - SPCTRM_H1_ESTIMATOR: Uses an H1 estimate.
        !!
        !!  - SPCTRM_H2_ESTIMATOR: Uses an H2 estimate.
        !!
        !! If an unrecognized value is provided, the routine defaults to an 
        !! H1 estimator.
    integer(int32), intent(in), optional :: nfft
        !! An optional input that can be used to force the length of each
        !! individual DFT operation by padding any remaining space with zeros.
        !! If not supplied, the window size is used to determine the size of
        !! the DFT.
    complex(real64), allocatable :: rst(:)
        !! Returns the complex-valued transfer function estimate.

    ! Local Variables
    integer(int32) :: est
    complex(real64), allocatable, dimension(:) :: pcross
    real(real64), allocatable, dimension(:) :: pwr
    
    ! Initialization
    if (present(etype)) then
        est = etype
    else
        est = SPCTRM_H1_ESTIMATOR
    end if
    if (est /= SPCTRM_H1_ESTIMATOR .and. est /= SPCTRM_H2_ESTIMATOR) then
        est = SPCTRM_H1_ESTIMATOR
    end if

    ! Process
    select case (est)
    case (SPCTRM_H1_ESTIMATOR)
        pcross = csd(win, y, x, nfft = nfft)
        pwr = psd(win, x, nfft = nfft)
        rst = pcross / pwr
    case (SPCTRM_H2_ESTIMATOR)
        pcross = csd(win, x, y, nfft = nfft)
        pwr = psd(win, y)
        rst = pwr / pcross
    end select
end function

! ------------------------------------------------------------------------------
end module